<template>
  <div>
    <PageWrapper contentBackground :dense="true" :contentFullHeight="true">
      <div class="header_button">
        <a-button type="primary" style="margin-right: 20px" @click="saveGraph">{{
          t('common.saveText')
        }}</a-button>
      </div>
      <div class="content">
        <div class="app-stencil" ref="stencilContainer" id="stencilContainer"> </div>
        <div class="app-content" ref="graphContainer" id="graphContainer"> </div>
      </div>
      <!-- 自定义标签弹窗 -->
      <Modal
        :title="t('routes.demo.workFlow.flowModelPage.customLabel')"
        v-model:visible="visible"
        @ok="handleOk"
        @cancel="handleCancel"
        :maskClosable="false"
      >
        <div style="display: flex; justify-content: center; align-items: center">
          <Select v-model:value="title" default-value="成功" style="width: 60%">
            <SelectOption value="成功">{{
              t('routes.demo.workFlow.flowModelPage.success')
            }}</SelectOption>
            <SelectOption value="失败">{{
              t('routes.demo.workFlow.flowModelPage.fail')
            }}</SelectOption>
          </Select>
        </div>
      </Modal>
      <!-- 步骤属性 -->
      <Modal
        :title="t('routes.demo.workFlow.flowModelPage.stepProperty')"
        v-model:visible="stepVisible"
        @ok="handleOkStep"
        @cancel="handleCancelStep"
        :maskClosable="false"
      >
        <div style="height: 500px; overflow: auto" id="stepOption">
          <Tabs type="card">
            <TabPane key="1" :tab="t('routes.demo.workFlow.flowModelPage.basicProperty')">
              <Row>
                <Col :span="20">
                  <Form :model="form" :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
                    <FormItem :label="t('routes.demo.workFlow.flowModelPage.code')">
                      <Input v-model:value="form.shortid" readOnly />
                    </FormItem>
                    <FormItem :label="t('routes.demo.workFlow.flowModelPage.name')">
                      <Input v-model:value="form.name" />
                    </FormItem>
                    <FormItem :label="t('routes.demo.workFlow.flowModelPage.workDescription')">
                      <Textarea
                        v-model:value="form.description"
                        :autosize="{ minRows: 3, maxRows: 5 }"
                      />
                    </FormItem>
                    <FormItem :label="t('routes.demo.workFlow.flowModelPage.HandleWay')">
                      <Select v-model:value="form.process">
                        <SelectOption :value="7">
                          {{ t('routes.demo.workFlow.flowModelPage.selectPrincipal') }}
                        </SelectOption>
                        <SelectOption :value="1">
                          {{ t('routes.demo.workFlow.flowModelPage.selectPrincipalInTemplate') }}
                        </SelectOption>
                      </Select>
                    </FormItem>
                    <FormItem :label="t('routes.demo.workFlow.flowModelPage.principal')">
                      <Select v-model:value="form.actor">
                        <SelectOption
                          v-for="(item, index) in personList"
                          :value="item.id"
                          :key="index"
                        >
                          {{ item.name }}
                        </SelectOption>
                      </Select>
                    </FormItem>
                    <FormItem label=" " :colon="false">
                      <Checkbox v-model:checked="form.check1">{{
                        t('routes.demo.workFlow.flowModelPage.adjustObject')
                      }}</Checkbox>
                    </FormItem>
                    <FormItem label=" " :colon="false">
                      <Checkbox v-model:checked="form.check2">{{
                        t('routes.demo.workFlow.flowModelPage.editObject')
                      }}</Checkbox>
                    </FormItem>
                    <FormItem label=" " :colon="false">
                      <Checkbox v-model:checked="form.check3">{{
                        t('routes.demo.workFlow.flowModelPage.addReferenceDocument')
                      }}</Checkbox>
                    </FormItem>
                    <FormItem label=" " :colon="false">
                      <Checkbox v-model:checked="form.check4">{{
                        t('routes.demo.workFlow.flowModelPage.downloadReferenceDocument')
                      }}</Checkbox>
                    </FormItem>
                    <FormItem label=" " :colon="false">
                      <Checkbox v-model:checked="form.check5">{{
                        t('routes.demo.workFlow.flowModelPage.noSelectPrincipal')
                      }}</Checkbox>
                    </FormItem>
                    <FormItem label=" " :colon="false">
                      <Checkbox v-model:checked="form.check6">{{
                        t('routes.demo.workFlow.flowModelPage.mustAddObject')
                      }}</Checkbox>
                    </FormItem>
                    <FormItem :label="t('routes.demo.workFlow.flowModelPage.multiStepJudge')">
                      <Select v-model:value="form.routerOnEntry">
                        <SelectOption :value="0">
                          {{ t('routes.demo.workFlow.flowModelPage.and') }}
                        </SelectOption>
                        <SelectOption :value="1">
                          {{ t('routes.demo.workFlow.flowModelPage.or') }}
                        </SelectOption>
                      </Select>
                    </FormItem>
                  </Form>
                </Col>
                <Col :span="4">
                  <a-button style="margin-top: 267px">...</a-button>
                </Col>
              </Row>
            </TabPane>
          </Tabs>
        </div>
      </Modal>
    </PageWrapper>
  </div>
</template>
<script lang="ts" setup>
  import { onMounted, ref } from 'vue';
  import { Graph, Addon, Shape } from '@antv/x6';
  import { PageWrapper } from '/@/components/Page';
  import {
    Modal,
    Select,
    SelectOption,
    Tabs,
    TabPane,
    Row,
    Col,
    Form,
    FormItem,
    Input,
    Checkbox,
  } from 'ant-design-vue';
  import { useRoute, useRouter } from 'vue-router';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { addFlowTemplateApi, updateFlowTemplateApi } from '/@/api/demo/flow';
  import { Getallpersondto } from '/@/api/demo/system';
  import { useMultipleTabStore } from '/@/store/modules/multipleTab';
  import { useI18n } from '/@/hooks/web/useI18n';

  const { t } = useI18n();

  const tabStore = useMultipleTabStore();
  const Textarea = Input.TextArea;
  const form: any = ref({
    shortid: '',
    name: '',
    description: '',
    process: 7,
    actor: '',
    check1: false,
    check2: false,
    check3: false,
    check4: false,
    check5: false,
    check6: false,
    routerOnEntry: 1,
  });

  const { createMessage } = useMessage();
  const { Edge } = Shape;
  const graphs: any = ref(null);
  const newArr: any = ref({});
  const title: any = ref('成功');
  const visible = ref(false);
  const stepVisible = ref(false);
  const newNodeArr: any = ref({});
  const updateShortId = ref('');
  const liststep: any = ref([]);
  const weblist: any = ref({});
  const mainwfdto: any = ref({});
  const savelist: any = ref({});
  const personList = ref<any>([]);

  const route: any = useRoute();
  const router: any = useRouter();

  // 数据初始化
  const initData = () => {
    if (
      route.params.form !== undefined ||
      route.params.weblist !== undefined ||
      route.params.liststep !== undefined
    ) {
      mainwfdto.value = JSON.parse(route.params.form);
      weblist.value = JSON.parse(route.params.weblist);
      liststep.value = JSON.parse(route.params.liststep);
    }
  };

  // 人员数据
  Getallpersondto().then((res) => {
    personList.value = res;
  });

  initData();
  // 生命周期
  onMounted(() => {
    initGraph();
    getDataList();
  });

  // 保存
  const saveGraph = () => {
    if (weblist.value.length === 0) {
      // 新增
      weblist.value = graphs.value.toJSON();
      savelist.value = graphs.value.toJSON();
      let addList: any = {
        mainwfdto: mainwfdto.value,
        weblist: weblist.value.cells,
        liststep: liststep.value,
        savelist: savelist.value,
      };
      addFlowTemplateApi(addList);
      createMessage.success(t('common.addSuccessText'));
      clearGraph();
      const targetKey = tabStore.tabList.find((item) => item.name === route.name).fullPath;
      tabStore.closeTabByKey(targetKey.toString(), router);
      router.push({ name: 'flowTemplate' });
    } else {
      // 修改
      weblist.value = graphs.value.toJSON();
      savelist.value = graphs.value.toJSON();
      // api 接口
      let updateList: any = {
        mainwfdto: mainwfdto.value,
        weblist: weblist.value.cells,
        liststep: liststep.value,
        savelist: savelist.value,
      };
      updateFlowTemplateApi(updateList);
      createMessage.success(t('common.editSuccessText'));
      clearGraph();
      const targetKey = tabStore.tabList.find((item) => item.name === route.name).fullPath;
      tabStore.closeTabByKey(targetKey.toString(), router);
      router.push({ name: 'flowTemplate' });
    }
  };
  const getDataList = () => {
    graphs.value.fromJSON(weblist.value);
  };

  const clearGraph = () => {
    liststep.value = [];
    mainwfdto.value = {};
    weblist.value = {};
    savelist.value = {};
  };
  const initGraph = () => {
    // 初始化画布
    let graphContainer: any = document.getElementById('graphContainer');
    const graph = new Graph({
      container: graphContainer,
      background: false, // 设置画布背景颜色
      grid: {
        type: 'dot', // 网格类型 'dot' | 'fixedDot' | 'mesh'
        size: 20, // 网格大小 10px
        visible: true, // 渲染网格背景
      },

      // 配置连线规则
      connecting: {
        // 路由将边的路径点 vertices 做进一步转换处理，并在必要时添加额外的点，然后返回处理后的点，默认值为 normal。
        router: {
          name: 'manhattan',
          args: {
            padding: 1,
          },
        },
        // 连接器将起点、路由返回的点、终点加工为 元素的 d 属性，决定了边渲染到画布后的样式，默认值为 normal。
        connector: {
          name: 'rounded',
          args: {
            radius: 8,
          },
        },
        anchor: 'center', // 当连接到节点时，通过 anchor 来指定被连接的节点的锚点，默认值为 center。
        connectionPoint: 'anchor', // 指定连接点，默认值为 boundary。
        allowBlank: false, //是否允许连接到画布空白位置的点
        // 当 snap 设置为 true 时连线的过程中距离节点或者连接桩 20px 时会触发自动吸附
        snap: {
          radius: 20,
        },
        // 连接的过程中创建新的边
        createEdge() {
          return new Edge({
            attrs: {
              line: {
                stroke: '#A2B1C3',
                strokeWidth: 2,
                targetMarker: {
                  name: 'block',
                  width: 12,
                  height: 8,
                },
              },
            },
            zIndex: 0,
          });
        },
        // 在移动边的时候判断连接是否有效，如果返回 false，当鼠标放开的时候，不会连接到当前元素，否则会连接到当前元素
        validateConnection({ targetMagnet }) {
          return !!targetMagnet;
        },
      },
      //拖动边时，是否高亮显示所有可用的节点
      highlighting: {
        //连线过程中，自动吸附到链接桩时被使用
        magnetAdsorbed: {
          name: 'stroke',
          args: {
            attrs: {
              fill: '#5F95FF',
              stroke: '#5F95FF',
            },
          },
        },
      },
      resizing: true, // 缩放节点，默认禁用。开启后可以对节点进行缩放
      rotating: true, // 旋转节点，默认禁用。开启后可以对节点进行旋转。
      // 点选/框选，默认禁用。创建画布时，通过以下配置开启选择交互，开启后可以通过点击或者套索框选节点。
      selecting: {
        enabled: true,
        rubberband: true, //是否启用框选，默认为 false。
        showNodeSelectionBox: true, // 是否显示节点的选择框，默认为 false。
      },
      snapline: {
        enabled: true, //对齐线
        tolerance: 10, //对齐精度
      },
      keyboard: true, // 键盘快捷键，默认禁用。
      clipboard: true, // 剪切板，默认禁用
      history: {
        enabled: true, //撤销/重做
        ignoreAdd: false, //是否忽略添加
        ignoreRemove: false, //是否忽略添加
        ignoreChange: false, //是否忽略属性变化
      },
      mousewheel: {
        enabled: true, // 支持滚动放大缩小
        zoomAtMousePosition: true, // 是否将鼠标位置作为中心缩放
        modifiers: 'ctrl', //修饰键('alt'、'ctrl'、'meta'、'shift')
        minScale: 0.5,
        maxScale: 3,
      },
      // panning: {
      //     enabled: true, // 支持画布平移
      // },
    });
    // 回显graph数据
    graphs.value = graph;
    // 初始化 stencil
    let sideOptions: any = document.getElementById('stencilContainer');
    const stencil = new Addon.Stencil({
      title: '全部组件',
      target: graph, //目标画布
      search: true, // 搜索选项
      placeholder: '搜索', //搜索文本框的 placeholder 文本
      notFoundText: '没有找到匹配项', //未匹配到搜索结果时的提示文本
      collapsable: true, //是否显示全局折叠/展开按钮
      stencilGraphWidth: 250, //模板画布宽度
      stencilGraphHeight: 300, //模板画布高度
      //分组信息
      groups: [
        {
          name: 'group1', // 分组名称
          title: '流程组件', // 分组标题，缺省时使用 `name`
        },
      ],
      layoutOptions: {
        columns: 2,
        columnWidth: 100,
        rowHeight: 70,
      },
    });
    sideOptions.appendChild(stencil.container);

    // 快捷键与事件
    // 复制
    graph.bindKey(['meta+c', 'ctrl+c'], () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.copy(cells);
      }
      return false;
    });
    // 剪切
    graph.bindKey(['meta+x', 'ctrl+x'], () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.cut(cells);
      }
      return false;
    });
    // 粘贴
    graph.bindKey(['meta+v', 'ctrl+v'], () => {
      if (!graph.isClipboardEmpty()) {
        const cells = graph.paste({ offset: 32 });
        graph.cleanSelection();
        graph.select(cells);
      }
      return false;
    });
    // 撤销
    graph.bindKey(['meta+z', 'ctrl+z'], () => {
      if (graph.history.canUndo()) {
        graph.history.undo();
      }
      return false;
    });
    // 重做
    graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
      if (graph.history.canRedo()) {
        graph.history.redo();
      }
      return false;
    });
    // 选择全部
    graph.bindKey(['meta+a', 'ctrl+a'], () => {
      const nodes = graph.getNodes();
      if (nodes) {
        graph.select(nodes);
      }
    });

    // 删除
    graph.bindKey(['backspace', 'delete'], () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.removeCells(cells);
      }
    });

    // 缩放
    graph.bindKey(['ctrl+1', 'meta+1'], () => {
      const zoom = graph.zoom();
      if (zoom < 1.5) {
        graph.zoom(0.1);
      }
    });
    graph.bindKey(['ctrl+2', 'meta+2'], () => {
      const zoom = graph.zoom();
      if (zoom > 0.5) {
        graph.zoom(-0.1);
      }
    });

    // 控制连接桩显示/隐藏
    const showPorts = (ports, show) => {
      for (let i = 0, len = ports.length; i < len; i = i + 1) {
        ports[i].style.visibility = show ? 'visible' : 'hidden';
      }
    };
    graph.on('node:mouseenter', () => {
      const ports = graphContainer.querySelectorAll('.x6-port-body');
      showPorts(ports, true);
    });
    graph.on('node:mouseleave', () => {
      const ports = graphContainer.querySelectorAll('.x6-port-body');
      showPorts(ports, false);
    });
    // 自定义边标签
    graph.on('edge:dblclick', (e: any) => {
      newArr.value = e.edge;
      if (e.edge.labels.length != 0) {
        title.value = e.edge.labels[0].attrs.label.text;
      }
      visible.value = true;
    });
    // 连线新增事件
    graph.on('edge:added', (e) => {
      e.edge.setLabels([{ attrs: { label: { text: '成功' } } }]);
    });
    // 右击事件打开弹窗属性
    graph.on('node:contextmenu', (e: any) => {
      newNodeArr.value = e.node;
      updateShortId.value = e.node.label;
      let newObj: any = liststep.value.find((item) => item.shortid == e.node.id);
      let newAttrstr = newObj.attrstr.split('').map((element) => element == '1');
      form.value.shortid = newObj.shortid;
      form.value.name = newObj.name;
      form.value.description = newObj.description;
      form.value.process = newObj.process;
      form.value.actor = newObj.actor;
      form.value.check1 = newAttrstr[0];
      form.value.check2 = newAttrstr[1];
      form.value.check3 = newAttrstr[2];
      form.value.check4 = newAttrstr[3];
      form.value.check5 = newAttrstr[4];
      form.value.check6 = newAttrstr[5];
      form.value.routerOnEntry = newObj.routerOnEntry;
      stepVisible.value = true;
    });
    // 节点添加事件
    graph.on('node:added', (e: any) => {
      const newArr = {
        shortid: e.node.id,
        name: e.node.label,
        description: '',
        process: 7,
        actor: '',
        attrstr: '000000',
        routerOnEntry: 1,
      };
      liststep.value.push(newArr);
    });
    // 节点移除事件
    graph.on('node:removed', (e) => {
      liststep.value = liststep.value.filter((item) => item.shortid !== e.node.id);
    });
    // 初始化图形
    const ports = {
      groups: {
        top: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
        bottom: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
      },
      items: [
        {
          group: 'top',
        },
        {
          group: 'right',
        },
        {
          group: 'bottom',
        },
        {
          group: 'left',
        },
      ],
    };
    Graph.registerNode(
      'custom-rect',
      {
        inherit: 'rect',
        width: 70,
        height: 40,
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#5F95FF',
            fill: '#EFF4FF',
          },
          text: {
            fontSize: 12,
            fill: '#262626',
          },
        },
        ports: { ...ports },
      },
      true,
    );
    Graph.registerNode(
      'custom-polygon',
      {
        inherit: 'polygon',
        width: 66,
        height: 36,
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#5F95FF',
            fill: '#EFF4FF',
          },
          text: {
            fontSize: 12,
            fill: '#262626',
          },
        },
        ports: {
          ...ports,
          items: [
            {
              group: 'top',
            },
            {
              group: 'bottom',
            },
          ],
        },
      },
      true,
    );
    Graph.registerNode(
      'custom-circle',
      {
        inherit: 'circle',
        width: 45,
        height: 45,
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#5F95FF',
            fill: '#EFF4FF',
          },
          text: {
            fontSize: 12,
            fill: '#262626',
          },
        },
        ports: { ...ports },
      },
      true,
    );

    Graph.registerNode(
      'custom-image',
      {
        inherit: 'rect',
        width: 52,
        height: 52,
        markup: [
          {
            tagName: 'rect',
            selector: 'body',
          },
          {
            tagName: 'image',
          },
          {
            tagName: 'text',
            selector: 'label',
          },
        ],
        attrs: {
          body: {
            stroke: '#5F95FF',
            fill: '#5F95FF',
          },
          image: {
            width: 26,
            height: 26,
            refX: 13,
            refY: 16,
          },
          label: {
            refX: 3,
            refY: 2,
            textAnchor: 'left',
            textVerticalAnchor: 'top',
            fontSize: 12,
            fill: '#fff',
          },
        },
        ports: { ...ports },
      },
      true,
    );
    const star = graph.createNode({
      shape: 'custom-circle',
      label: '开始',
    });
    const end = graph.createNode({
      shape: 'custom-circle',
      label: '结束',
    });
    const process = graph.createNode({
      shape: 'custom-rect',
      attrs: {
        body: {
          rx: 6,
          ry: 6,
        },
      },
      label: '可选过程',
    });
    const judge = graph.createNode({
      shape: 'custom-polygon',
      attrs: {
        body: {
          refPoints: '0,10 10,0 20,10 10,20',
        },
      },
      label: '决策',
    });
    stencil.load([star, end, process, judge], 'group1');
  };

  // 标签弹窗
  const handleOk = () => {
    if (newArr.value.labels.length == 0) {
      newArr.value.setLabels([{ attrs: { label: { text: title.value } } }]);
    } else {
      newArr.value.setLabels([{ attrs: { label: { text: title.value } } }]);
    }
    handleCancel();
  };
  const handleCancel = () => {
    title.value = '成功';
    visible.value = false;
  };

  // 步骤属性
  const handleOkStep = () => {
    liststep.value.forEach((element) => {
      if (element.shortid == updateShortId.value) {
        newNodeArr.value.label = form.value.name;
        element.shortid = form.value.name;
        element.name = form.value.name;
        element.description = form.value.description;
        element.process = form.value.process;
        element.actor = form.value.actor;
        element.attrstr =
          (form.value.check1 ? '1' : '0') +
          (form.value.check2 ? '1' : '0') +
          (form.value.check3 ? '1' : '0') +
          (form.value.check4 ? '1' : '0') +
          (form.value.check5 ? '1' : '0') +
          (form.value.check6 ? '1' : '0');
        element.routerOnEntry = form.value.routerOnEntry;
      }
    });
    handleCancelStep();
  };
  const handleCancelStep = () => {
    stepVisible.value = false;
    form.value.shortid = '';
    form.value.name = '';
    form.value.description = '';
    form.value.process = 7;
    form.value.actor = '';
    form.value.routerOnEntry = 1;
    form.value.check1 = false;
    form.value.check2 = false;
    form.value.check3 = false;
    form.value.check4 = false;
    form.value.check5 = false;
    form.value.check6 = false;
    let stepOption: any = document.getElementById('stepOption');
    stepOption.scrollTop = 0;
  };
</script>
<style lang="less" scoped>
  .header_button {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    height: 50px;
    margin-top: 10px;
    box-shadow: 0 0 10px 1px #e9e9e9;
  }

  .content {
    font-family: sans-serif;
    display: flex;
    margin-top: 10px;
  }

  .app-stencil {
    width: 250px;
    height: 750px;
    border: 1px solid #f0f0f0;
    position: relative;
  }

  .app-content {
    flex: 1;
    width: 100%;
    height: 750px;
    margin-left: 8px;
    margin-right: 8px;
    box-shadow: 0 0 10px 1px #e9e9e9;
  }

  .x6-widget-stencil {
    background-color: #fff;
  }

  .x6-widget-stencil-title {
    background-color: #fff;
  }

  .x6-widget-stencil-group-title {
    background-color: #fff !important;
  }

  .x6-widget-transform {
    margin: -1px 0 0 -1px;
    padding: 0;
    border: 1px solid #239edd;
  }

  .x6-widget-transform > div {
    border: 1px solid #239edd;
  }

  .x6-widget-transform > div:hover {
    background-color: #3dafe4;
  }

  .x6-widget-transform-active-handle {
    background-color: #3dafe4;
  }

  .x6-widget-transform-resize {
    border-radius: 0;
  }

  .x6-widget-selection-inner {
    border: 1px solid #239edd;
  }

  .x6-widget-selection-box {
    opacity: 0%;
  }
</style>
